///////////////////////////////////////////////////////////////////////////////////////////////////
/// \file formic/fqmc/linear_method.h
///
/// \brief   header file for the linear method optimizer
///
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef FORMIC_FQMC_LINEAR_METHOD_HEADER
#define FORMIC_FQMC_LINEAR_METHOD_HEADER

#include<boost/shared_ptr.hpp>

#include<formic/random/random.h>

namespace formic {

  class InputBase;
  class Configuration;
  template<class S> class CoeffObj;

  namespace fqmc {

    template<class S> class Sampler;

    //template<class S> void linear_method(const formic::InputBase & userinp, const boost::shared_ptr<formic::CoeffObj<S> > & co);
    //template<class S> void linear_method_old(const formic::InputBase & userinp, const boost::shared_ptr<formic::CoeffObj<S> > & co);

    ///////////////////////////////////////////////////////////////////////////////////////////////////
    /// \brief  A class to perform a linear method update of the current wave function
    ///
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    template <class S> class LinMethodUpdater {

      private:

        /// \brief  a list of shifts to apply to the diagonal of the first derivative supspace Hamiltonian
        std::vector<double> _h_shifts;

        double _step_size;

        bool update_3_together(const formic::InputBase & userinp,
                               const boost::shared_ptr<formic::fqmc::Sampler<S> > & input_sampler,
                               const boost::shared_ptr<formic::CoeffObj<S> > & vf);

      public:

        LinMethodUpdater(const formic::InputBase & userinp);

        bool update(const formic::InputBase & userinp,
                    boost::shared_ptr<formic::fqmc::Sampler<S> > & sampler,
                    const boost::shared_ptr<formic::CoeffObj<S> > & co);

    };

  }

}

#endif
